/**
 * 文件模型
 * File Model
 */

const BaseModel = require('./BaseModel');
const path = require('path');
const fs = require('fs').promises;
const logger = require('../../utils/logger');
const config = require('../../config/config');

class File extends BaseModel {
  constructor() {
    super('files');
  }

  /**
   * 创建文件记录
   */
  async createFile(userId, fileData) {
    try {
      const fileToCreate = {
        user_id: userId,
        filename: fileData.filename,
        original_name: fileData.original_name,
        file_path: fileData.file_path,
        file_size: fileData.file_size,
        mime_type: fileData.mime_type,
        file_type: this.getFileType(fileData.mime_type),
        folder_path: fileData.folder_path || '/',
        is_public: fileData.is_public || 0,
        thumbnail_path: fileData.thumbnail_path || null,
        metadata: fileData.metadata ? JSON.stringify(fileData.metadata) : null
      };

      const file = await this.create(fileToCreate);
      
      logger.info('文件记录创建成功 / File record created successfully', {
        fileId: file.id,
        userId,
        filename: file.filename,
        fileSize: file.file_size
      });

      return file;
    } catch (error) {
      logger.error('创建文件记录失败 / Failed to create file record', {
        userId,
        filename: fileData.filename,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 获取用户文件列表
   */
  async getUserFiles(userId, options = {}) {
    try {
      const {
        page = 1,
        pageSize = 20,
        folderPath = '/',
        fileType = null,
        orderBy = 'created_at DESC',
        includeDeleted = false
      } = options;

      const conditions = { 
        user_id: userId,
        folder_path: folderPath
      };
      
      if (!includeDeleted) {
        conditions.is_deleted = 0;
      }
      
      if (fileType) {
        conditions.file_type = fileType;
      }

      return await this.paginate(conditions, {
        page,
        pageSize,
        orderBy,
        fields: 'id, filename, original_name, file_size, mime_type, file_type, folder_path, is_public, download_count, thumbnail_path, created_at, updated_at'
      });
    } catch (error) {
      logger.error('获取用户文件列表失败 / Failed to get user files', {
        userId,
        folderPath: options.folderPath,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 获取文件详情
   */
  async getFileDetail(fileId, userId) {
    try {
      const file = await this.findOne({
        id: fileId,
        user_id: userId,
        is_deleted: 0
      });

      if (!file) {
        throw new Error('文件不存在 / File not found');
      }

      // 解析元数据
      if (file.metadata) {
        try {
          file.metadata = JSON.parse(file.metadata);
        } catch (e) {
          file.metadata = null;
        }
      }

      return file;
    } catch (error) {
      logger.error('获取文件详情失败 / Failed to get file detail', {
        fileId,
        userId,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 更新文件信息
   */
  async updateFile(fileId, userId, updateData) {
    try {
      // 验证文件所有权
      const existingFile = await this.findOne({
        id: fileId,
        user_id: userId,
        is_deleted: 0
      });

      if (!existingFile) {
        throw new Error('文件不存在或无权限 / File not found or no permission');
      }

      const dataToUpdate = {
        updated_at: new Date()
      };

      // 只更新提供的字段
      if (updateData.original_name !== undefined) {
        dataToUpdate.original_name = updateData.original_name;
      }
      
      if (updateData.folder_path !== undefined) {
        dataToUpdate.folder_path = updateData.folder_path;
      }
      
      if (updateData.is_public !== undefined) {
        dataToUpdate.is_public = updateData.is_public ? 1 : 0;
      }
      
      if (updateData.metadata !== undefined) {
        dataToUpdate.metadata = updateData.metadata ? JSON.stringify(updateData.metadata) : null;
      }

      const updatedFile = await this.update(fileId, dataToUpdate);

      logger.info('文件信息更新成功 / File info updated successfully', {
        fileId,
        userId,
        filename: updatedFile.filename
      });

      return updatedFile;
    } catch (error) {
      logger.error('更新文件信息失败 / Failed to update file info', {
        fileId,
        userId,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 软删除文件
   */
  async deleteFile(fileId, userId) {
    try {
      // 验证文件所有权
      const existingFile = await this.findOne({
        id: fileId,
        user_id: userId,
        is_deleted: 0
      });

      if (!existingFile) {
        throw new Error('文件不存在或无权限 / File not found or no permission');
      }

      await this.update(fileId, {
        is_deleted: 1,
        deleted_at: new Date()
      });

      logger.info('文件删除成功 / File deleted successfully', {
        fileId,
        userId,
        filename: existingFile.filename
      });

      return existingFile;
    } catch (error) {
      logger.error('删除文件失败 / Failed to delete file', {
        fileId,
        userId,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 永久删除文件（包括物理文件）
   */
  async permanentDeleteFile(fileId, userId) {
    try {
      // 验证文件所有权
      const existingFile = await this.findOne({
        id: fileId,
        user_id: userId
      });

      if (!existingFile) {
        throw new Error('文件不存在或无权限 / File not found or no permission');
      }

      // 删除物理文件
      try {
        await fs.unlink(existingFile.file_path);
        
        // 如果有缩略图，也删除
        if (existingFile.thumbnail_path) {
          await fs.unlink(existingFile.thumbnail_path);
        }
      } catch (fsError) {
        logger.warn('删除物理文件失败 / Failed to delete physical file', {
          filePath: existingFile.file_path,
          error: fsError.message
        });
      }

      // 删除数据库记录
      await this.delete(fileId);

      logger.info('文件永久删除成功 / File permanently deleted', {
        fileId,
        userId,
        filename: existingFile.filename
      });

      return true;
    } catch (error) {
      logger.error('永久删除文件失败 / Failed to permanently delete file', {
        fileId,
        userId,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 移动文件到指定文件夹
   */
  async moveFile(fileId, userId, newFolderPath) {
    try {
      const existingFile = await this.findOne({
        id: fileId,
        user_id: userId,
        is_deleted: 0
      });

      if (!existingFile) {
        throw new Error('文件不存在或无权限 / File not found or no permission');
      }

      await this.update(fileId, {
        folder_path: newFolderPath,
        updated_at: new Date()
      });

      logger.info('文件移动成功 / File moved successfully', {
        fileId,
        userId,
        oldPath: existingFile.folder_path,
        newPath: newFolderPath
      });

      return true;
    } catch (error) {
      logger.error('移动文件失败 / Failed to move file', {
        fileId,
        userId,
        newFolderPath,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 增加文件下载次数
   */
  async incrementDownloadCount(fileId) {
    try {
      const sql = 'UPDATE files SET download_count = download_count + 1 WHERE id = ?';
      await this.raw(sql, [fileId]);
    } catch (error) {
      logger.error('增加文件下载次数失败 / Failed to increment download count', {
        fileId,
        error: error.message
      });
      // 不抛出错误，因为这不是关键操作
    }
  }

  /**
   * 搜索文件
   */
  async searchFiles(userId, keyword, options = {}) {
    try {
      const { page = 1, pageSize = 20, fileType = null } = options;
      const offset = (page - 1) * pageSize;

      let sql = `
        SELECT id, filename, original_name, file_size, mime_type, file_type, folder_path, 
               is_public, download_count, thumbnail_path, created_at, updated_at
        FROM files 
        WHERE user_id = ? 
          AND is_deleted = 0 
          AND (filename LIKE ? OR original_name LIKE ?)
      `;
      
      const params = [userId, `%${keyword}%`, `%${keyword}%`];
      
      if (fileType) {
        sql += ' AND file_type = ?';
        params.push(fileType);
      }
      
      sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
      params.push(pageSize, offset);

      const { rows } = await this.raw(sql, params);

      // 获取总数
      let countSql = `
        SELECT COUNT(*) as total 
        FROM files 
        WHERE user_id = ? 
          AND is_deleted = 0 
          AND (filename LIKE ? OR original_name LIKE ?)
      `;
      
      const countParams = [userId, `%${keyword}%`, `%${keyword}%`];
      
      if (fileType) {
        countSql += ' AND file_type = ?';
        countParams.push(fileType);
      }

      const { rows: countRows } = await this.raw(countSql, countParams);
      const total = countRows[0].total;

      return {
        data: rows,
        pagination: {
          page,
          pageSize,
          total,
          totalPages: Math.ceil(total / pageSize)
        }
      };
    } catch (error) {
      logger.error('搜索文件失败 / Failed to search files', {
        userId,
        keyword,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 获取用户文件统计
   */
  async getUserFileStats(userId) {
    try {
      const sql = `
        SELECT 
          COUNT(*) as total_files,
          COUNT(CASE WHEN is_deleted = 1 THEN 1 END) as deleted_files,
          COUNT(CASE WHEN file_type = 'image' THEN 1 END) as image_files,
          COUNT(CASE WHEN file_type = 'video' THEN 1 END) as video_files,
          COUNT(CASE WHEN file_type = 'audio' THEN 1 END) as audio_files,
          COUNT(CASE WHEN file_type = 'document' THEN 1 END) as document_files,
          SUM(file_size) as total_size,
          AVG(file_size) as avg_size,
          SUM(download_count) as total_downloads
        FROM files 
        WHERE user_id = ?
      `;

      const { rows } = await this.raw(sql, [userId]);
      return rows[0];
    } catch (error) {
      logger.error('获取用户文件统计失败 / Failed to get user file stats', {
        userId,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 获取文件夹列表
   */
  async getFolders(userId, parentPath = '/') {
    try {
      const sql = `
        SELECT DISTINCT folder_path
        FROM files 
        WHERE user_id = ? 
          AND is_deleted = 0 
          AND folder_path LIKE ?
          AND folder_path != ?
        ORDER BY folder_path
      `;

      const searchPattern = parentPath === '/' ? '/%' : `${parentPath}/%`;
      const { rows } = await this.raw(sql, [userId, searchPattern, parentPath]);

      // 提取直接子文件夹
      const folders = new Set();
      rows.forEach(row => {
        const relativePath = row.folder_path.substring(parentPath.length);
        const parts = relativePath.split('/').filter(part => part);
        if (parts.length > 0) {
          folders.add(parts[0]);
        }
      });

      return Array.from(folders).sort();
    } catch (error) {
      logger.error('获取文件夹列表失败 / Failed to get folders', {
        userId,
        parentPath,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 获取最近上传的文件
   */
  async getRecentFiles(userId, limit = 10) {
    try {
      return await this.findMany(
        { user_id: userId, is_deleted: 0 },
        {
          fields: 'id, filename, original_name, file_type, file_size, created_at',
          orderBy: 'created_at DESC',
          limit
        }
      );
    } catch (error) {
      logger.error('获取最近上传文件失败 / Failed to get recent files', {
        userId,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 根据MIME类型确定文件类型
   */
  getFileType(mimeType) {
    if (mimeType.startsWith('image/')) {
      return 'image';
    } else if (mimeType.startsWith('video/')) {
      return 'video';
    } else if (mimeType.startsWith('audio/')) {
      return 'audio';
    } else if (
      mimeType.includes('pdf') ||
      mimeType.includes('document') ||
      mimeType.includes('text') ||
      mimeType.includes('spreadsheet') ||
      mimeType.includes('presentation')
    ) {
      return 'document';
    } else {
      return 'other';
    }
  }

  /**
   * 检查文件是否存在
   */
  async checkFileExists(userId, filename, folderPath = '/') {
    try {
      const file = await this.findOne({
        user_id: userId,
        filename: filename,
        folder_path: folderPath,
        is_deleted: 0
      });

      return !!file;
    } catch (error) {
      logger.error('检查文件存在性失败 / Failed to check file existence', {
        userId,
        filename,
        folderPath,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 生成唯一文件名
   */
  async generateUniqueFilename(userId, originalFilename, folderPath = '/') {
    try {
      const ext = path.extname(originalFilename);
      const baseName = path.basename(originalFilename, ext);
      
      let filename = originalFilename;
      let counter = 1;

      while (await this.checkFileExists(userId, filename, folderPath)) {
        filename = `${baseName}_${counter}${ext}`;
        counter++;
      }

      return filename;
    } catch (error) {
      logger.error('生成唯一文件名失败 / Failed to generate unique filename', {
        userId,
        originalFilename,
        error: error.message
      });
      throw error;
    }
  }
}

module.exports = new File();